"""
管理器
"""
import threading

import redis
import json
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from functools import partial


# 如何确保每一个网站都单独运行？
class CookieServer:
    """
    封装一层管理器集中管理cookie
    """
    def __init__(self, settings):
        # 设置decode_responses防止取回来的数据是byte类型
        self.redis_cli = redis.Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, decode_responses=True)
        self.service_list = []  # 需要启动的服务
        self.settings = settings

    def register(self, cls):
        """
        将需要启动的服务注册进来，cls从settings中获取，获取回来的是一个类
        :param cls:
        :return:
        """
        self.service_list.append(cls)

    def login_service(self, srv):
        # while 1:
        srv_cli = srv(self.settings)  # 实例化，要把settings传进来
        srv_name = srv_cli.webname
        account = self.settings.Accounts[srv_name]  # 将账户信息从settings中取出

        # 将现有cookie数量返回回来
        cookie_nums = self.redis_cli.scard(account['cookie_key'])
        if cookie_nums < account['max_cookie_nums']:
            cookie_dict = srv_cli.login()
            self.redis_cli.sadd(account['cookie_key'], json.dumps(cookie_dict))
        else:
            print(f"{srv_name} 的cookie池已满，等待10s")
            time.sleep(10)

    def check_cookie_service(self, srv):
        # while 1:
        print("开始检测cookie是否可用")
        srv_cli = srv(self.settings)  # 实例化，要把settings传进来
        srv_name = srv_cli.webname
        account = self.settings.Accounts[srv_name]  # 将账户信息从settings中取出

        # 获取cookie池中所有cookie
        all_cookies = self.redis_cli.smembers(account['cookie_key'])
        print(f"目前可用cookie数量: {len(all_cookies)}")

        # 判断cookie池中的cookie是否有效
        for cookie_str in all_cookies:
            print(f"获取cookie值: {cookie_str}")
            cookie_dict = json.loads(cookie_str)  # 一定要转换成字典
            if srv_cli.check_cookie(cookie_dict):
                print(f"cookie: {cookie_str} 有效")
            else:
                print(f"cookie: {cookie_str} 失效，删除cookie")
                self.redis_cli.srem(account['cookie_key'], cookie_str)

            # 设置时间间隔，防止请求过于频繁，导致原本没有失效的cookie失效了
            print(f"{account['check_interval']} 秒后重新开始检测cookie有效性")
            time.sleep(account['check_interval'])

    def start(self):
        """
        使用线程池启动服务
        :return:
        """
        task_list = []
        print("启动登录服务")
        login_executor = ThreadPoolExecutor(max_workers=5)
        for srv1 in self.service_list:
            # task_list.append(login_executor.submit(self.login_service, srv))  # 上下两种方式选一种，最好选下面这种
            task_list.append(login_executor.submit(partial(self.login_service, srv1)))

        print("启动cookie检测服务")
        check_cookie_executor = ThreadPoolExecutor(max_workers=5)
        for srv1 in self.service_list:
            task_list.append(check_cookie_executor.submit(partial(self.check_cookie_service, srv1)))

        # 防止服务关闭
        for future in as_completed(task_list):
            print(future.result())
